package br.edu.ufcg.embedded.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

public class Compressor
{
	private final String ENCODER = "UTF-8";
	//private int compressedDataLength;
	private final int MAX_LENGTH = 1024 * 1024;
	
	public Compressor()
	{
	}
	
	
/*	public byte[] compress(String text)
	{
		// Encode a String into bytes
		byte[] input = null;
		
		try {
			input = text.getBytes(ENCODER);
			// Compress the bytes
			byte[] output = new byte[MAX_LENGTH];
			Deflater compresser = new Deflater();
			compresser.setInput(input);
			compresser.finish();
			compressedDataLength = compresser.deflate(output);
			
			return output;
			
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	public String decompress(byte[] output)
	{
		// Decompress the bytes
		Inflater decompresser = new Inflater();
		decompresser.setInput(output, 0, compressedDataLength);
		
		byte[] result = new byte[MAX_LENGTH];
		
		int resultLength;
		try {
			resultLength = decompresser.inflate(result);
			decompresser.end();
			// Decode the bytes into a String
			String outputString = new String(result, 0, resultLength, ENCODER);
			
			return outputString;
			
		} catch (DataFormatException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	public String decompress(byte[] output, int compressedDataLength)
	{
		// Decompress the bytes
		Inflater decompresser = new Inflater();
		decompresser.setInput(output, 0, compressedDataLength);
		
		byte[] result = new byte[MAX_LENGTH];
		
		int resultLength;
		try {
			resultLength = decompresser.inflate(result);
			decompresser.end();
			// Decode the bytes into a String
			String outputString = new String(result, 0, resultLength, ENCODER);
			
			return outputString;
			
		} catch (DataFormatException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		return null;
	
	
	public int getCompressedDataLength()
	{
		return compressedDataLength;
	}
}*/
	
	public byte[] compress(byte[] data)
	{
		byte[] result = null;
		
		try {
			// Create the compressor with highest level of compression
			Deflater compressor = new Deflater();
			compressor.setLevel(Deflater.BEST_SPEED);

			// Give the compressor the data to compress
			compressor.setInput(data);
			compressor.finish();

			// Create an expandable byte array to hold the compressed data.
			// You cannot use an array that's the same size as the orginal because
			// there is no guarantee that the compressed data will be smaller than
			// the uncompressed data.
			ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
			
			// Compress the data
			byte[] buf = new byte[MAX_LENGTH];
			
			while (!compressor.finished()) {
			    int count = compressor.deflate(buf);
			    bos.write(buf, 0, count);
			}
			
			bos.flush();
			bos.close();
			compressor.end();
			
			result = bos.toByteArray();
			
			buf = null;
			compressor = null;
			bos = null;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		
		return result;
	}
	
	public byte[] compress(String text)
	{
		byte[] result = null;
		
		try {
			byte[] input = text.getBytes(ENCODER);
			text = null;
			// Create the compressor with highest level of compression
			Deflater compressor = new Deflater();
			compressor.setLevel(Deflater.BEST_SPEED);

			// Give the compressor the data to compress
			compressor.setInput(input);
			compressor.finish();

			// Create an expandable byte array to hold the compressed data.
			// You cannot use an array that's the same size as the orginal because
			// there is no guarantee that the compressed data will be smaller than
			// the uncompressed data.
			ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);
			
			// Compress the data
			byte[] buf = new byte[MAX_LENGTH];
			
			while (!compressor.finished()) {
			    int count = compressor.deflate(buf);
			    bos.write(buf, 0, count);
			}
			
			bos.flush();
			bos.close();
			compressor.end();
			
			result = bos.toByteArray();
			
			buf = null;
			compressor = null;
			bos = null;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		
		return result;
	}
	
	public byte[] decompressData(byte[] compressedData)
	{
		try
		{
			// Create the decompressor and give it the data to compress
			Inflater decompressor = new Inflater();
			decompressor.setInput(compressedData);

			// Create an expandable byte array to hold the decompressed data
			ByteArrayOutputStream bos = new ByteArrayOutputStream(compressedData.length);

			// Decompress the data
			byte[] buf = new byte[MAX_LENGTH];

			while (!decompressor.finished()) {
				int count = decompressor.inflate(buf);
				bos.write(buf, 0, count);
			}
			bos.flush();
			bos.close();
			
			// Get the decompressed data
			byte[] decompressedData = bos.toByteArray();
			
			bos = null;
			compressedData = null;
			
			return decompressedData;

		} catch (DataFormatException e) {
			e.getStackTrace();
		} catch (IOException e1) {
			e1.getStackTrace();
		}
		return null;
	}
	
	public String decompress(byte[] compressedData)
	{
		try
		{
			// Create the decompressor and give it the data to compress
			Inflater decompressor = new Inflater();
			decompressor.setInput(compressedData);

			// Create an expandable byte array to hold the decompressed data
			ByteArrayOutputStream bos = new ByteArrayOutputStream(compressedData.length);

			// Decompress the data
			byte[] buf = new byte[MAX_LENGTH];

			while (!decompressor.finished()) {
				int count = decompressor.inflate(buf);
				bos.write(buf, 0, count);
			}
			bos.close();
			// Get the decompressed data
			byte[] decompressedData = bos.toByteArray();
			return new String(decompressedData, 0, decompressedData.length, ENCODER);

		} catch (DataFormatException e) {
			e.getStackTrace();
		} catch (IOException e1) {
			e1.getStackTrace();
		}
		return null;
	}
}
